/*
 * $Id: string_rotate.c,v 1.1 2005-09-17 11:22:53 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/wstring.h>
#else
#include <xp/bas/string.h>
#endif

xp_size_t xp_strrot (xp_char_t* str, int dir, xp_size_t n)
{
	return xp_strxrot (str, xp_strlen(str), dir, n);
}

/*
xp_size_t xp_strxrot (xp_char_t* str, xp_size_t len, int dir, xp_size_t n)
{
	xp_size_t i, j, k;
	xp_char_t c, c2;

	if (len <= 1) return len;
	if ((n %= len) == 0) return len;

	if (n > len / 2) {
		/ *dir *= -1;* /
		dir = ~dir + 1;
		n = len - n;
	}

	if (dir < 0) {
		for (k = 0, j = 0; j < len; k++) {
			i = k; c = str[i];
			do {
				if (n > i) i = i + len - n;
				else i = i - n;

				c2 = str[i]; str[i] = c; c = c2;
				j++;
			} while (i != k);
		}
	}
	else if (dir > 0) {
		for (k = 0, j = 0; j < len; k++) {
			i = k; c = str[i];
			do {
				/ *i = (i + n) % len;* /
				i += n; if (i >= len) i -= len;

				c2 = str[i]; str[i] = c; c = c2;
				j++;
			} while (i != k);
		}
	}

	return len;
}
*/

xp_size_t xp_strxrot (xp_char_t* str, xp_size_t len, int dir, xp_size_t n)
{
	xp_size_t first, last, count, index, nk;
	xp_char_t c;

	if (dir == 0) return len;
	if ((n %= len) == 0) return len;

	if (dir > 0) n = len - n;
	first = 0; nk = len - n; count = 0; 

	while (count < n) {
		last = first + nk;
		index = first;
		c = str[first];
		while (1) {
			count++;
			while (index < nk) {
				str[index] = str[index + n];
				index += n;
			}
			if (index == last) break;
			str[index] = str[index - nk];
			index -= nk;
		}
		str[last] = c; first++;
	}

	return len;
}

xp_size_t xp_strrev (xp_char_t* str)
{
	return xp_strxrev (str, xp_strlen(str));
}

xp_size_t xp_strxrev (xp_char_t* str, xp_size_t len)
{
	xp_char_t ch;
	xp_char_t* start = str;
	xp_char_t* end = str + len - 1;

	while (start < end) {
		ch = *start;
		*start++ = *end;
		*end-- = ch;	
	}

	return len;
}
